﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Forest.Cat.Domain.Entities;
using Forest.Core.Data;
using Forest.Core;
using Forest.Cat.Domain.Configuration;
using Forest.Core.Caching;
using Forest.Core.Events;
using Forest.Cat.Domain.Shared;
using Forest.Cat.Domain.Entities.Messages;

namespace Forest.Cat.Domain.Services.Catalog {
    public partial class JobPositionService : IJobPositionService {
        #region Constants

        #endregion

        #region Fields

        private readonly IRepository<JobPosition> _jobPositionRepository;
        //private readonly IRepository<JobCategory> _jobCategoryRepository;
        private readonly IRepository<Application> _applicationRepository;
        private readonly IRepository<SavedJob> _savedJobRepository;
        private readonly IRepository<Company> _companyRepository;
        private readonly ILovService _lovService;
        private readonly ICacheManager _cacheManager;
        private readonly IEventPublisher _eventPublisher;
        private readonly IRepository<ReceivedMessage> _receivedMessageRepository;

        #endregion

        #region Ctor
        public JobPositionService(ILovService lovService,
            IRepository<JobPosition> jobPositionRepository,
            //IRepository<JobCategory> jobCategoryRepository,
            IRepository<Application> applicationRepository,
            IRepository<SavedJob> savedJobRepository,
            IRepository<Company> companyRepository,
            IRepository<ReceivedMessage> receivedMessageRepository,
            ICacheManager cacheManager,
            IEventPublisher eventPublisher) {
            _lovService = lovService;
            _jobPositionRepository = jobPositionRepository;
            //_jobCategoryRepository = jobCategoryRepository;
            _applicationRepository = applicationRepository;
            _savedJobRepository = savedJobRepository;
            _companyRepository = companyRepository;
            _receivedMessageRepository = receivedMessageRepository;
            _cacheManager = cacheManager;
            _eventPublisher = eventPublisher;
        }
        #endregion

        #region Base Methods
        public virtual void DeleteJobPosition(JobPosition jobposition) {
            if (jobposition == null)
                throw new ArgumentNullException("JobPosition");

            _jobPositionRepository.Delete(jobposition);
        }

        public JobPosition GetJobPositionById(Guid jobpositionId) {
            if (jobpositionId == Guid.Empty)
                return null;
            return _jobPositionRepository.GetById(jobpositionId);
        }

        public virtual IPagedList<JobPosition> GetAllJobPositions(int pageIndex, int pageSize) {
            var query = _jobPositionRepository.Table;
            query = query.OrderBy(w => w.Id);
            var items = new PagedList<JobPosition>(query, pageIndex, pageSize);
            return items;
        }

        public virtual void InsertJobPosition(JobPosition jobposition) {
            if (jobposition == null)
                throw new ArgumentNullException("JobPosition");
            _jobPositionRepository.Insert(jobposition);
        }

        public virtual void UpdateJobPosition(JobPosition jobposition) {
            if (jobposition == null)
                throw new ArgumentNullException("JobPosition");
            _jobPositionRepository.Update(jobposition);
        }
        #endregion

        #region Extend Methods

        public IList<JobPosition> GetHotJobList() {
            var query = from p in _jobPositionRepository.Table
                        where p.IsHot
                        orderby p.Reposted
                        select p;

            var jobs = query.ToList();
            return jobs;
        }

        #region 获取职位的分页列表
        public IPagedList<JobPosition> GetJobPagedList(
           int pageIndex,
           int pageSize,
           IQueryable<JobPosition> query) {
            return new PagedList<JobPosition>(query, pageIndex, pageSize);
        }
        #endregion

        #region 高级检索
        public IQueryable<JobPosition> AdvSearchJobList(String keyWord,
            int? industry1,
            int? industry2,
            int? jobCategory1,
            int? jobCategory2,
            String educationLevelString,
            String jobTypeString,
            int? companyType,
            int? postedDate,
            JobListOrderMode orderMode,
            String lovCondition = null) {
            keyWord = keyWord ?? String.Empty;
            var resultList = from job in GetActiveJobList()
                             join company in _companyRepository.Table
                             on job.CompanyId equals company.Id
                             where (job.JobTitle + company.CompanyName).Contains(keyWord)
                             select new { job, company };
            //公司行业
            if (industry1.HasValue && industry2.HasValue) {
                resultList = resultList.Where(x => x.company.Industry.Value.Equals(industry1.Value) || x.company.Industry.Value.Equals(industry2.Value));
            }
            else if (industry1.HasValue) {
                resultList = resultList.Where(x => x.company.Industry.Value.Equals(industry1.Value));
            }
            else if (industry2.HasValue) {
                resultList = resultList.Where(x => x.company.Industry.Value.Equals(industry2.Value));
            }
            //职位类别
            if (jobCategory1.HasValue && jobCategory2.HasValue) {
                resultList = resultList.Where(x => x.job.Category.Equals(jobCategory1.Value) || x.job.Category.Equals(jobCategory2.Value));
            }
            else if (jobCategory1.HasValue) {
                resultList = resultList.Where(x => x.job.Category.Equals(jobCategory1.Value));
            }
            else if (jobCategory2.HasValue) {
                resultList = resultList.Where(x => x.job.Category.Equals(jobCategory2.Value));
            }
            //教育程度
            if (!String.IsNullOrWhiteSpace(educationLevelString)) {
                var educationLevelList = educationLevelString.Split(',').Where(x => !String.IsNullOrWhiteSpace(x)).Select(x => int.Parse(x));
                if (educationLevelList.Any()) {
                    resultList = resultList.Where(x => educationLevelList.Contains(x.job.EducationLevel.Value));
                }
            }
            //职位类型
            if (!String.IsNullOrWhiteSpace(jobTypeString)) {
                var jobTypeList = jobTypeString.Split(',').Where(x => !String.IsNullOrWhiteSpace(x)).Select(x => int.Parse(x));
                if (jobTypeList.Any()) {
                    resultList = resultList.Where(x => jobTypeList.Contains(x.job.JobType));
                }
            }
            //公司性质
            if (companyType.HasValue) {
                resultList = resultList.Where(x => x.company.CompanyType.Value.Equals(companyType.Value));
            }
            //发布日期
            if (postedDate.HasValue) {
                var dateFrom = _lovService.GetPostedDate(postedDate.Value);
                if (dateFrom.HasValue) {
                    var dateTo = DateTime.Now.Date;
                    resultList = resultList.Where(x => x.job.StartDate.Value >= dateFrom && x.job.StartDate.Value <= dateTo);
                }
            }
            var jobList = resultList.Select(x => x.job);
            //进行Lov类型的查询
            if (!String.IsNullOrWhiteSpace(lovCondition)) {
                jobList = AddLovCondition(jobList, lovCondition);
            }
            jobList = AddOrderCondition(jobList, orderMode);
            return jobList;
        }
        #endregion

        #region 检索Job一览(前台)
        /// <summary>
        /// 检索Job一览(前台)
        /// </summary>
        /// <param name="jobName"></param>
        /// <param name="category"></param>
        /// <returns></returns>
        public IQueryable<JobPosition> FindJobList(String jobTitle, String companyName, JobListOrderMode orderMode, String lovCondition = null) {
            var resultList = from job in GetActiveJobList()
                             join company in _companyRepository.Table
                             on job.CompanyId equals company.Id
                             where job.JobTitle.Contains(jobTitle) &&
                             company.CompanyName.Contains(companyName)
                             select new { job, company };
            var jobList = resultList.Select(x => x.job);
            if (!String.IsNullOrWhiteSpace(lovCondition)) {
                jobList = AddLovCondition(jobList, lovCondition);
            }
            jobList = AddOrderCondition(jobList, orderMode);
            return jobList;
        }
        #endregion

        #region 追加排序筛选条件
        /// <summary>
        /// 追加排序筛选条件
        /// </summary>
        /// <param name="jobList"></param>
        /// <param name="orderMode"></param>
        /// <returns></returns>
        private IQueryable<JobPosition> AddOrderCondition(IQueryable<JobPosition> jobList, JobListOrderMode orderMode) {
            if (orderMode == JobListOrderMode.Reposted) {
                return jobList.OrderByDescending(item => item.Reposted);
            }
            else {
                var minDate = DateTime.Now.Date;
                switch (orderMode) {
                    case JobListOrderMode.OneDay:
                        minDate = minDate.AddDays(-1);
                        break;
                    case JobListOrderMode.ThreeDay:
                        minDate = minDate.AddDays(-3);
                        break;
                    case JobListOrderMode.OneWeek:
                        minDate = minDate.AddDays(-7);
                        break;

                    case JobListOrderMode.TwoWeek:
                        minDate = minDate.AddDays(-14);
                        break;
                }
                return jobList.Where(x => x.StartDate.Value > minDate).OrderByDescending(item => item.StartDate.Value);
            }
        }
        #endregion

        #region 在职位结果集上附加Lov类型的查询
        /// <summary>
        /// 在职位结果集上附加Lov类型的查询
        /// </summary>
        /// <param name="jobList"></param>
        /// <param name="lovType"></param>
        /// <param name="lovValue"></param>
        /// <returns></returns>
        private IQueryable<JobPosition> AddLovCondition(IQueryable<JobPosition> jobList, String lovCondition) {
            var resultList = from job in jobList
                             join company in _companyRepository.Table
                             on job.CompanyId equals company.Id
                             select new { job, company };
            var lovConditionList = lovCondition.Split('|').Where(x => !String.IsNullOrWhiteSpace(x)).ToList();
            lovConditionList.ForEach(x => {
                var lovType = (LovType)Enum.Parse(typeof(LovType), x.Split('-')[0]);
                var lovValue = int.Parse(x.Split('-')[1]);
                switch (lovType) {
                    case LovType.JobCategory:
                        resultList = resultList.Where(item => item.job.Category.Equals(lovValue));
                        break;
                    case LovType.YearsOfExperience:
                        resultList = resultList.Where(item => item.job.YearsOfExperience.HasValue && item.job.YearsOfExperience.Value.Equals(lovValue));
                        break;
                    case LovType.EducationLevel:
                        resultList = resultList.Where(item => item.job.EducationLevel.HasValue && item.job.EducationLevel.Value.Equals(lovValue));
                        break;
                    case LovType.SalaryRange:
                        //如果选中了面议，则取出薪水不公开的记录
                        if (lovValue == ConstManager.NegotiableValue) {
                            resultList = resultList.Where(item => !item.job.IsOpenSalaryRange);
                        }
                        else {
                            resultList = resultList.Where(item => item.job.IsOpenSalaryRange && item.job.SalaryRange.Value.Equals(lovValue));
                        }
                        break;
                    //发布日期
                    //公司性质
                    case LovType.CompanyType:
                        resultList = resultList.Where(item => item.company.CompanyType.HasValue && item.company.CompanyType.Value.Equals(lovValue));
                        break;
                    case LovType.JobType:
                        resultList = resultList.Where(item => item.job.JobType.Equals(lovValue));
                        break;
                    case LovType.ParentCategory:
                        resultList = resultList.Where(item => item.job.ParentCategory.Equals(lovValue));
                        break;
                }
            });
            return resultList.Select(item => item.job);
        }
        #endregion

        #region 获取职位相关Lov列表

        /// <summary>
        /// 获取职位相关Lov列表
        /// </summary>
        /// <param name="jobTitle"></param>
        /// <param name="companyName"></param>
        /// <param name="lovType"></param>
        /// <returns></returns>
        public IList<LovInfoForSearchListView> GetLovInfoList(String jobTitle, String companyName, LovType lovType, JobListOrderMode orderMode, String lovCondition) {
            var jobList = FindJobList(jobTitle, companyName, orderMode, lovCondition);
            return DoGetLovInfoList(jobList, lovType);
        }

        /// <summary>
        /// 获取职位相关Lov列表
        /// </summary>
        /// <param name="keyWord"></param>
        /// <param name="industry1"></param>
        /// <param name="industry2"></param>
        /// <param name="jobCategory1"></param>
        /// <param name="jobCategory2"></param>
        /// <param name="educationLevelString"></param>
        /// <param name="jobTypeString"></param>
        /// <param name="companyType"></param>
        /// <param name="postedDate"></param>
        /// <param name="lovType"></param>
        /// <returns></returns>
        public IList<LovInfoForSearchListView> GetLovInfoList(String keyWord,
            int? industry1,
            int? industry2,
            int? jobCategory1,
            int? jobCategory2,
            String educationLevelString,
            String jobTypeString,
            int? companyType,
            int? postedDate,
            LovType lovType,
            JobListOrderMode orderMode,
            String lovCondition) {
            var jobList = AdvSearchJobList(keyWord,
                industry1,
                industry2,
                jobCategory1,
                jobCategory2,
                educationLevelString,
                jobTypeString,
                companyType,
                postedDate,
                orderMode,
                lovCondition);
            return DoGetLovInfoList(jobList, lovType);
        }

        /// <summary>
        /// 执行获取职位相关Lov列表操作
        /// </summary>
        /// <param name="jobTitle"></param>
        /// <returns></returns>
        private IList<LovInfoForSearchListView> DoGetLovInfoList(IQueryable<JobPosition> jobList, LovType lovType) {
            List<LovInfoForSearchListView> groupList = null;
            IEnumerable<LovInfoForSearchListView> tempList = null;
            var resultList = from job in jobList
                             join company in _companyRepository.Table
                             on job.CompanyId equals company.Id
                             select new { job, company };
            switch (lovType) {
                case LovType.JobCategory:
                    tempList = resultList.GroupBy(i => i.job.Category).Select(i => new LovInfoForSearchListView { Value = i.Key, Total = i.Count() });
                    break;
                case LovType.YearsOfExperience:
                    tempList = resultList.Where(i => i.job.YearsOfExperience.HasValue).
                        GroupBy(i => i.job.YearsOfExperience).Select(i => new LovInfoForSearchListView { Value = i.Key.Value, Total = i.Count() });
                    break;
                case LovType.EducationLevel:
                    tempList = resultList.Where(i => i.job.EducationLevel.HasValue).
                        GroupBy(i => i.job.EducationLevel).Select(i => new LovInfoForSearchListView { Value = i.Key.Value, Total = i.Count() });
                    break;
                case LovType.SalaryRange:
                    tempList = resultList.Where(i => i.job.SalaryRange.HasValue).
                        GroupBy(i => i.job.IsOpenSalaryRange ? i.job.SalaryRange : ConstManager.NegotiableValue).Select(i => new LovInfoForSearchListView { Value = i.Key.Value, Total = i.Count() });
                    break;
                //发布日期
                //公司性质
                case LovType.CompanyType:
                    tempList = resultList.Where(i => i.company.CompanyType.HasValue).
                        GroupBy(i => i.company.CompanyType).Select(i => new LovInfoForSearchListView { Value = i.Key.Value, Total = i.Count() });
                    break;
                case LovType.JobType:
                    tempList = resultList.GroupBy(i => i.job.JobType).Select(i => new LovInfoForSearchListView { Value = i.Key, Total = i.Count() });
                    break;
            }
            groupList = tempList.ToList();
            groupList.ForEach(item => {
                var lov = _lovService.GetAll().FirstOrDefault(i => i.Value.Equals(item.Value));
                if (lov != null) {
                    item.Name = lov.Name;
                    item.ParentId = lov.ParentId;
                }
            });
            return groupList;
        }

        #endregion

        #region 获取公司的职位一览
        /// <summary>
        /// 获取公司的职位一览
        /// </summary>
        /// <param name="companyId"></param>
        /// <returns></returns>
        public IQueryable<JobPosition> GetJobListByCompanyId(Guid companyId) {
            var currentDate = DateTime.Now.Date;
            return GetActiveJobList().Where(x => x.CompanyId.Value.Equals(companyId));
        }
        #endregion

        #region 获取和传入的职位相同行业的职位列表(排除传入的职位)
        /// <summary>
        /// 获取和传入的职位相同行业的职位列表(排除传入的职位)
        /// </summary>
        /// <param name="jobId"></param>
        /// <returns></returns>
        public IQueryable<JobPosition> GetRelatedJobList(Guid jobId) {
            var currentDate = DateTime.Now.Date;
            var categoryValue = _jobPositionRepository.Table.FirstOrDefault(x => x.Id.Equals(jobId)).Category;
            return from job in GetActiveJobList()
                   where job.Category.Equals(categoryValue) &&
                       //排除传入的Job
                       !job.Id.Equals(jobId)
                   select job;
        }
        #endregion

        #region 根据访问记录获取职位信息
        /// <summary>
        /// 根据访问记录获取职位信息
        /// </summary>
        /// <param name="jobIdList"></param>
        /// <returns></returns>
        public IQueryable<JobPosition> GetJobsRelatedByViewdHistory(IEnumerable<Guid> jobIdList) {
            //对应的职位分类
            var categoryList = _jobPositionRepository.Table.Where(x => jobIdList.Contains(x.Id)).Select(x => x.Category).Distinct();

            //找出相关的职位信息(排除已经收藏或申请的职位)
            var resultList = from job in GetActiveJobList()
                             where categoryList.Contains(job.Category) &&
                                 !jobIdList.Contains(job.Id)
                             select job;
            return resultList;
        }
        #endregion

        #region 获取和求职人相关的职位信息
        /// <summary>
        /// 获取和求职人相关的职位信息
        /// </summary>
        /// <param name="jobSeekerId"></param>
        /// <returns></returns>
        public IQueryable<JobPosition> GetJobsRelatedByJobSeeker(Guid jobSeekerId) {
            //申请的职位
            var applicationJobIdList = _applicationRepository.Table.Select(x => x.JobPositionId);
            //收藏的职位 
            var savedJobIdList = _savedJobRepository.Table.Select(x => x.JobPositionId);
            //对应的职位分类
            var categoryList = (from job in _jobPositionRepository.Table
                                join application in _applicationRepository.Table
                                on new { JobseekerId = jobSeekerId, JobPositionId = job.Id }
                                equals new { application.JobseekerId, application.JobPositionId } into applicationGroup
                                from applicationItem in applicationGroup.DefaultIfEmpty()
                                join savedJob in _savedJobRepository.Table
                                on new { JobseekerId = jobSeekerId, JobPositionId = job.Id }
                                equals new { savedJob.JobseekerId, savedJob.JobPositionId } into savedJobGroup
                                from savedJobItem in savedJobGroup.DefaultIfEmpty()
                                where (applicationItem != null || savedJobItem != null)
                                select job.Category).Distinct();
            IQueryable<JobPosition> resultList = null;
            if (categoryList.Any()) {
                //找出相关的职位信息(排除已经收藏或申请的职位)
                resultList = from job in _jobPositionRepository.Table
                             join categoryValue in categoryList
                             on job.Category equals categoryValue
                             join application in _applicationRepository.Table
                             on new { JobseekerId = jobSeekerId, JobPositionId = job.Id }
                             equals new { application.JobseekerId, application.JobPositionId } into applicationGroup
                             from applicationItem in applicationGroup.DefaultIfEmpty()
                             join savedJob in _savedJobRepository.Table
                             on new { JobseekerId = jobSeekerId, JobPositionId = job.Id }
                             equals new { savedJob.JobseekerId, savedJob.JobPositionId } into savedJobGroup
                             from savedJobItem in savedJobGroup.DefaultIfEmpty()
                             where applicationItem == null && savedJobItem == null
                             select job;
            }
            else {
                //找出相关的职位信息(排除已经收藏或申请的职位)
                resultList = _jobPositionRepository.Table;
            }
            var status = (int)Status.Publish;
            var now = DateTime.Now.Date;
            //return resultList.Where(x => x.Status == status && now >= x.StartDate.Value && now <= x.EndDate);
            return resultList.Where(x => x.Status == status && now <= x.EndDate);
        }
        #endregion

        #region 查询显示首页的列表
        /// <summary>
        /// 查询显示首页的列表
        /// </summary>
        /// <returns></returns>
        public IQueryable<JobPosition> GetAdminIndexList(Guid jobSeekerId) {
            return GetJobsRelatedByJobSeeker(jobSeekerId);
        }
        #endregion

        #region 获取激活的职位列表
        /// <summary>
        /// 获取激活的职位列表
        /// </summary>
        /// <returns></returns>
        private IQueryable<JobPosition> GetActiveJobList(JobSource jobSource = JobSource.NCHR) {
            var status = (int)Status.Publish;
            var currentDate = DateTime.Now.Date;
            //return _jobPositionRepository.Table.Where(x => x.StartDate.HasValue &&
            //            x.StartDate.Value.Date.CompareTo(currentDate)<=0 &&
            //            x.EndDate.Date.CompareTo(currentDate) >=0 &&
            //            x.Status == 1);
            return _jobPositionRepository.Table.Where(x => x.StartDate.HasValue &&
                //x.StartDate <= currentDate &&
                      x.EndDate >= currentDate &&
                      x.Source == (int)jobSource &&
                      x.Status == status);
        }
        #endregion

        #region 获取当前人员收到的企业来信
        /// <summary>
        /// 获取当前人员收到的企业来信
        /// </summary>
        /// <param name="jobseekerId"></param>
        /// <returns></returns>
        public IQueryable<ReceivedMessage> GetReceivedMessageList(Guid jobseekerId) {
            return _receivedMessageRepository.Table.Where(x => x.To.Equals(jobseekerId));
        }
        #endregion

        #endregion


        public IList<JobPosition> GetJobsBySource(JobSource jobSource, int top = 10) {
            return GetActiveJobList(jobSource).Take(top).ToList();
        }
    }
}
